﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using log4net;

namespace SimpleInfrastructure.Log
{
    public class Log4NetHelper
    {
        private static readonly ILog LogError;
        private static readonly ILog LogInfo;
        public static readonly bool CanLogError;
        public static readonly bool CanLogInfo;
        private static readonly object ErrorLogLock = new object();
        private static readonly object InfoLogLock = new object();
        private static readonly Queue<ErrorLogInfo> ErrorLogInfos = new Queue<ErrorLogInfo>();
        private static readonly Queue<string> InfoLogInfos = new Queue<string>();
        static Log4NetHelper()
        {
            Type mtype = typeof(Log4NetHelper);
            var dirpath = mtype.FullName.Substring(0, mtype.FullName.LastIndexOf('.'));
            string fileName = "log4net.xml";
            var logStream = mtype.Assembly.GetManifestResourceStream(string.Format("{0}.{1}", dirpath, fileName));
            log4net.Config.XmlConfigurator.Configure(logStream);
            LogError = log4net.LogManager.GetLogger("logerror");
            LogInfo = log4net.LogManager.GetLogger("loginfo");
            if (LogError != null && LogError.IsErrorEnabled)
            {
                CanLogError = true;
            }
            else
            {
                CanLogError = false;
            }
            if (LogInfo != null && LogInfo.IsInfoEnabled)
            {
                CanLogInfo = true;
            }
            else
            {
                CanLogInfo = false;
            }
            Work();
        }

        private static void Work()
        {
            if (CanLogError)
            {
                var terror = new Task(WriteError);
                terror.Start();
            }
            if (CanLogInfo)
            {
                var tinfo = new Task(WriteInfo);
                tinfo.Start();
            }
        }

        public class ErrorLogInfo
        {
            public string Info { set; get; }
            public Exception Error { set; get; }
        }

        public static void WriteError()
        {
            while (true)
            {
                try
                {
                    if (ErrorLogInfos != null && ErrorLogInfos.Count > 0)
                    {
                        ErrorLogInfo errorLogInfo = null;
                        lock (ErrorLogLock)
                        {
                            try
                            {
                                errorLogInfo = ErrorLogInfos.Dequeue();
                            }
                            catch (Exception ex)
                            {
                                errorLogInfo = null;
                            }

                        }
                        if (errorLogInfo != null)
                        {
                            if (errorLogInfo.Error != null)
                            {
                                var e = errorLogInfo.Error.GetBaseException();
                                StringBuilder sb = new StringBuilder();
                                if (!string.IsNullOrEmpty(errorLogInfo.Info))
                                {
                                    sb.AppendFormat("<span style='color: red; font-weight: bold;'>{0}</span><BR/>", errorLogInfo.Info);
                                }
                                sb.AppendFormat("<span style = 'background-color: gainsboro; font-weight: bold;'>{0}</span ><BR/>", e.Message);
                                if (!string.IsNullOrEmpty(e.StackTrace))
                                {
                                    sb.AppendFormat(e.StackTrace.Replace(System.Environment.NewLine, "<BR/>"));
                                }
                                string info = sb.ToString();
                                LogError.Error(info);
                            }
                            else
                            {
                                LogError.Error("<span style='color: red; font-weight: bold;'>" + errorLogInfo.Info + "</span>");
                            }
                        }
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }

        public static void WriteInfo()
        {
            while (true)
            {
                try
                {
                    if (InfoLogInfos != null && InfoLogInfos.Count > 0)
                    {
                        string info = null;
                        lock (InfoLogLock)
                        {
                            try
                            {
                                info = InfoLogInfos.Dequeue();
                            }
                            catch (Exception ex)
                            {
                                info = null;
                            }
                        }
                        if (!string.IsNullOrEmpty(info))
                        {
                            LogInfo.Error("<span style='color: red; font-weight: bold;'>" + info + "</span>");
                        }
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }

        public static void Info(string info)
        {
            if (CanLogInfo)
            {
                lock (InfoLogLock)
                {
                    InfoLogInfos.Enqueue(info);
                }
            }
        }

        public static void Error(string info)
        {
            if (CanLogError)
            {
                ErrorLogInfo errorLogInfo = new ErrorLogInfo { Info = info };
                lock (ErrorLogLock)
                {
                    ErrorLogInfos.Enqueue(errorLogInfo);
                }
            }
        }
        public static void Error(string info, Exception e)
        {
            if (CanLogError)
            {
                ErrorLogInfo errorLogInfo = new ErrorLogInfo { Info = info, Error = e };
                lock (ErrorLogLock)
                {
                    ErrorLogInfos.Enqueue(errorLogInfo);
                }
            }
        }
    }
}
